home *** CD-ROM | disk | FTP | other *** search
- ; MODULE XVSYNC
- ; Xlib comptible vsync handler
- ; Written by Tore Bastiansen
- ; based on REND386 by Dave Stampe and Bernie Roehl
-
- include xlib.inc
- include xmain.inc
- include xvsync.inc
-
-
- TIMER_VECT equ 08h
-
- PIC_CMD equ 20h
- NONSPEC_EOI equ 20h
- TIMER_MODE equ 34h
- TIMER_CONTROL equ 43h
- TIMER_0 equ 40h
-
- LATCH_COUNT equ 00h
-
- INT_IN_ADVANCE equ 100
-
- DOS_GETVECT equ 3500h
- DOS_SETVECT equ 2500h
-
-
- .data
- _TicksPerSecond dw 0
- _VsyncIntTicks label dword
- VsyncIntTicksLo dw 0
- VsyncIntTicksHi dw 0
- _VsyncPeriod dw 0 ;Time (in clicks) between each vsync
- ;1 click = 1.193 microseconds
-
- ClockRate dw 0 ;Clock rate (in clicks) for timer 0
- ClockCounter dw 0 ;Counts total clicks modulo 65536
- UserVsyncHandler label dword ;Pointer to user routine called
- UserVsyncOffs dw 0 ;called once each vsync period.
- UserVsyncSeg dw 0
- InUserHandler dw 0
- db 100h dup(?)
- LocalStack label byte ;Local stack for user handler
- StackSeg dw 0
- StackPtr dw 0
-
-
- ElapsedVrts dw 0
- VrtsToSkip dw 1
-
- .code
- get_vsync_period proc near
- mov al,TIMER_MODE ;Start timer
- out TIMER_CONTROL,al
- mov al,0
- out TIMER_0,al
- out TIMER_0,al
-
- WaitVsyncStart
-
- mov al,LATCH_COUNT
- out TIMER_CONTROL,al
- in al,TIMER_0
- mov cl,al
- in al,TIMER_0
- mov ch,al ;cx=65536-clicks
-
- WaitVsyncStart
-
- mov al,LATCH_COUNT
- out TIMER_CONTROL,al
- in al,TIMER_0
- mov dl,al
- in al,TIMER_0
- mov dh,al ;dx=65536-clicks
-
- sub cx,dx ;cx=clicks between two vsyncs
- mov ax,cx ;return in ax
- ret
- get_vsync_period endp
-
- vsync_int proc far
- pusha ;Save regs
- push ds
- push es
-
- mov ax,@data ;Set the right datasegment
- mov ds,ax
- add [VsyncIntTicksLo],1 ;Increment _VsyncIntTicks
- adc [VsyncIntTicksHi],0
-
- inc [ElapsedVrts]
- mov cx,[ElapsedVrts]
- cmp cx,[VrtsToSkip]
- jl @@StopClock
-
- cmp [_StartAddressFlag],1 ;Change in start address
- jne @@StopClock
-
- mov dx,CRTC_INDEX ;Yes, set start address
- mov ax,[_WaitingStartLow]
- mov bx,[_WaitingStartHigh]
- out dx,ax
- mov ax,bx
- out dx,ax
-
- @@StopClock:
- cli
- mov al,TIMER_MODE ;Stop the timer
- out TIMER_CONTROL,al ;Dont want any interrupts
- mov al,255
- out TIMER_0,al
- out TIMER_0,al
- sti
-
- cli
- mov dx,INPUT_STATUS_0 ;Wait for vsync
- @@WaitVS:
- in al,dx
- test al,08h
- jz @@WaitVS
-
- mov al,TIMER_MODE ;Start timer again
- out TIMER_CONTROL,al
- mov ax,[ClockRate]
- out TIMER_0,al
- mov al,ah
- out TIMER_0,al
-
- cmp cx,[VrtsToSkip]
- jl @@PaletteInt
-
- cmp [_StartAddressFlag],1 ;Any change in start address ?
- jne @@PaletteInt
-
- xor cx,cx
- mov [ElapsedVrts],cx
-
- mov ax,[_WaitingPelPan] ;Yes, set pel pan register
- mov dx,AC_INDEX
- out dx,al
- mov al,ah
- out dx,al
- mov [_StartAddressFlag],0
-
- @@PaletteInt:
- cmp [_VsyncPaletteCount],0 ;Any changes in the palette
- je @@MouseInt
- mov si, offset _VsyncPaletteBuffer ;Yes
- mov cx, [_VsyncPaletteCount]
- mov ax, [_VsyncPaletteStart]
- mov dx, DAC_WRITE_INDEX
- out dx, al
- mov dx, DAC_DATA
-
- @@DacOutLoop:
- outsb
- outsb
- outsb
- loop @@DacOutLoop
- mov [_VsyncPaletteCount],0
-
- @@MouseInt:
- cmp [_MouseRefreshFlag],1 ; Does the mouse need refresh
- jne @@UserInt
- call dword ptr [_MouseVsyncHandler] ; Yes
- ;(this is not yet implemented)
-
- @@UserInt:
- cmp [UserVsyncSeg], 0 ;Is the a user interrupt routine?
- je short @@Sim182
- cmp [InUserHandler],0 ;Yes, but is it already active?
- jne short @@Sim182
- mov [InUserHandler],1 ;No, mark it as active
- mov [StackSeg],ss ;make a local stack
- mov [StackPtr],sp
- push ds
- pop ss
- mov sp, offset LocalStack
- sti
- call dword ptr [UserVsyncHandler]
- cli
- mov sp, [StackPtr] ;Restore old stack
- mov ss, [StackSeg]
- mov [InUserHandler],0 ;Mark as not active
-
- ; SIM 18.2 Hz
- @@Sim182:
- mov ax,[_VsyncPeriod] ;Count number of clicks
- add [ClockCounter],ax ;If it is bigger than 65536
- jnc short @@DontChainOld
- pop es ;more than 1/18.2 secs has gone
- pop ds
- popa
- sti
- db 0eah ; jmp instruction
- OldTimerInt dd 0 ; Pointer to old int8 routine
- ; Selfmodyfiing code
- ;jmp dword ptr [OldTimerInt] Chain to old
- @@DontChainOld:
-
- ; CLEAN UP AND RETURN
- mov al,NONSPEC_EOI
- out PIC_CMD,al
-
-
- pop es
- pop ds
- popa
- sti
- iret
- vsync_int endp
-
-
- _x_install_vsync_handler proc
- ARG VrtSkipCount:word
- push bp
- mov bp,sp
- mov ax,[VrtSkipCount]
- or ax,ax
- jnz @@NonZeroCount
- mov ax,1
- @@NonZeroCount:
- mov [VrtsToSkip],ax
- mov [ElapsedVrts],0
- cmp [_VsyncHandlerActive],TRUE ;Is it already active
- je short @@Return
- call get_vsync_period ;no, get the vsync period
-
- mov [_VsyncPeriod],ax
- sub ax,INT_IN_ADVANCE ;We need a little extra
- mov [ClockRate],ax ;time
-
- mov dx,18 ;dx:ax=1193000
- mov ax,13352
- idiv [_VsyncPeriod]
- mov [_TicksPerSecond],ax ;1193/_VsyncPeriod
-
- mov word ptr [_VsyncIntTicks],0
- mov word ptr [_VsyncIntTicks+2],0
-
- cli
- mov ax, DOS_GETVECT+TIMER_VECT ;Get address of old timer int
- int 21h
- mov ax,es
- mov word ptr cs:[OldTimerInt],bx ;Store in OldTimerInt
- mov word ptr cs:[OldTimerInt+2],ax
-
- mov [_VsyncHandlerActive],TRUE ;Mark handler as active
- mov ax,DOS_SETVECT+TIMER_VECT ;Set the new timer int
- push ds
- mov dx,seg vsync_int
- mov ds,dx
- mov dx,offset vsync_int
- int 21h
- pop ds
-
- mov al,TIMER_MODE ;Reprogram timer 0
- out TIMER_CONTROL,al
- mov ax,ClockRate
- out TIMER_0,al
- mov al,ah
- out TIMER_0,al
- sti
- @@Return:
- pop bp
- ret
- _x_install_vsync_handler endp
-
- _x_remove_vsync_handler proc
- cmp [_VsyncHandlerActive],FALSE
- je short @@Return
- mov dx, word ptr cs:[OldTimerInt]
- mov ax, word ptr cs:[OldTimerInt+2]
- push ds
- mov ds,ax
- mov ax,DOS_SETVECT+TIMER_VECT ;Restore the old timer int
- cli
- int 21h
- pop ds
- mov al,TIMER_MODE ;Restore timer 0
- out TIMER_CONTROL,al
- mov al,0
- out TIMER_0,al
- out TIMER_0,al
- sti
- @@Return:
- ret
- _x_remove_vsync_handler endp
-
-
- ; WARNING: The user vsync handler cannot use the 386 specific registers
- ; (EAX,EBX,ECX,EDX,ESI,EDI,ESP,EBP,FS,GS)
- ; whithout saving them first.
- ; It must not do any drawing.
- ; Only 256 butes of stack is provided.
-
- _x_set_user_vsync_handler proc
- ARG handler_proc:dword
- push bp
- mov bp,sp
- mov ax, word ptr [handler_proc]
- mov dx, word ptr [handler_proc+2]
- cli
- mov word ptr [UserVsyncHandler],ax
- mov word ptr [UserVsyncHandler+2],dx
- sti
- pop bp
- ret
- _x_set_user_vsync_handler endp
-
- end
-